package com.tgy.postprocessor;

import com.tgy.annotation.Transaction;
import com.tgy.interceptor.Interceptor;
import com.tgy.interceptor.Invocation;
import com.tgy.interceptor.MethodInvocation;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.InvocationHandler;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.Map;

@Component
public class TransactionBeanPostProcessor implements BeanPostProcessor, ApplicationContextAware {

  private ApplicationContext applicationContext = null;

  @Override
  public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {

    Method[] declaredMethods = bean.getClass().getDeclaredMethods();

    boolean transactionFlag = false;
    for (Method declaredMethod : declaredMethods) {

      Transaction annotation = declaredMethod.getAnnotation(Transaction.class);
      if (annotation != null){

        transactionFlag = true;
        break;
      }
    }

    if (!transactionFlag){

      return bean;
    }

    Enhancer enhancer = new Enhancer();
    enhancer.setSuperclass(bean.getClass());
    enhancer.setCallback(new InvocationHandler() {
      @Override
      public Object invoke(Object o, Method method, Object[] objects) throws Throwable {

        Transaction annotation = method.getAnnotation(Transaction.class);

        if (annotation == null){

          return method.invoke(bean,objects);
        }

        Interceptor interceptor = applicationContext.getBean(Interceptor.class);
        if (interceptor == null){

          return method.invoke(bean,objects);
        }
        MethodInvocation methodInvocation = new MethodInvocation(bean, method, objects);
        return interceptor.invoke(methodInvocation);
      }
    });

    return enhancer.create();
  }

  @Override
  public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {

    this.applicationContext = applicationContext;
  }

}
